package com.atguigu.daijia.dispatch.xxl.client;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.dispatch.xxl.config.XxlJobClientProperties;
import com.atguigu.daijia.model.entity.dispatch.XxlJobInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

/**
 * @create: 2024/9/25
 * @author: gyhe10
 * @description: XXL-JOB 任务调度中心客户端
 **/

@Slf4j
@Component
@RequiredArgsConstructor
public class XxlJobClient {

    private final XxlJobClientProperties xxlJobClientProperties;
    private final RestTemplate restTemplate;

    /**
     * 添加任务
     * @param executorHandler
     * @param param
     * @param cron
     * @param desc
     * @return
     */
    public Long addJob(String executorHandler, String param, String cron, String desc) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setJobGroup(xxlJobClientProperties.getJobGroupId());
        xxlJobInfo.setJobDesc(desc);
        xxlJobInfo.setAuthor("gyhe10");
        // 调度类型：CRON
        xxlJobInfo.setScheduleType("CRON");
        xxlJobInfo.setScheduleConf(cron);
        // 运行模式：BEAN
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setExecutorHandler(executorHandler);
        xxlJobInfo.setExecutorParam(param);
        // 执行器路由策略：第一个执行器
        xxlJobInfo.setExecutorRouteStrategy("FIRST");
        // 阻塞处理策略：单机串行
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        // 调度过期策略：立即执行一次
        xxlJobInfo.setMisfireStrategy("FIRE_ONCE_NOW");
        // 任务超时时间
        xxlJobInfo.setExecutorTimeout(0);
        // 失败重试次数
        xxlJobInfo.setExecutorFailRetryCount(0);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, httpHeaders);

        String addUrl = xxlJobClientProperties.getAddJobUrl();
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(addUrl, request, JSONObject.class);
        if (response.getStatusCode().value() == 200 && response.getBody().getInteger("code") == 200) {
            log.info("增加 XXL-JOB 任务成功，返回信息：{}", response.getBody());
            // 返回任务 ID
            return response.getBody().getLong("content");
        }
        log.error("增加 XXL-JOB 任务失败，返回信息：{}", response.getBody().toJSONString());
        throw new GuiguException(ResultCodeEnum.XXL_JOB_FAIL);
    }

    /**
     * 启动任务
     * @param jobId
     * @return
     */
    public Boolean startJob(Long jobId) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setId(jobId.intValue());

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        String startUrl = xxlJobClientProperties.getStartJobUrl();
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(startUrl, request, JSONObject.class);
        if (response.getStatusCode().value() == 200 && response.getBody().getInteger("code") == 200) {
            log.info("启动 XXL-JOB 任务成功，任务 ID：{}，返回信息：{}", jobId, response.getBody().toJSONString());
            return true;
        }
        log.error("启动 XXL-JOB 任务失败，任务 ID：{}，返回信息：{}", jobId, response.getBody().toJSONString());
        throw new GuiguException(ResultCodeEnum.XXL_JOB_FAIL);
    }

    /**
     * 停止任务
     * @param jobId
     * @return
     */
    public Boolean stopJob(Long jobId) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setId(jobId.intValue());

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        String stopUrl = xxlJobClientProperties.getStopJobUrl();
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(stopUrl, request, JSONObject.class);
        if (response.getStatusCode().value() == 200 && response.getBody().getInteger("code") == 200) {
            log.info("停止 XXL-JOB 任务成功，任务 ID：{}，返回信息：{}", jobId, response.getBody().toJSONString());
            return true;
        }
        log.error("停止 XXL-JOB 任务失败，任务 ID：{}，返回信息：{}", jobId, response.getBody().toJSONString());
        throw new GuiguException(ResultCodeEnum.XXL_JOB_FAIL);
    }

    /**
     * 删除任务
     * @param jobId
     * @return
     */
    public Boolean removeJob(Long jobId) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setId(jobId.intValue());

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        String removeUrl = xxlJobClientProperties.getRemoveJobUrl();
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(removeUrl, request, JSONObject.class);
        if (response.getStatusCode().value() == 200 && response.getBody().getInteger("code") == 200) {
            log.info("删除 XXL-JOB 任务成功，任务 ID：{}，返回信息：{}", jobId, response.getBody().toJSONString());
            return true;
        }
        log.error("删除 XXL-JOB 任务失败，任务 ID：{}，返回信息：{}", jobId, response.getBody().toJSONString());
        throw new GuiguException(ResultCodeEnum.XXL_JOB_FAIL);
    }

    /**
     * 添加并启动任务
     * @param executorHandler
     * @param param
     * @param cron
     * @param desc
     * @return
     */
    public Long addAndStartJob(String executorHandler, String param, String cron, String desc) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setJobGroup(xxlJobClientProperties.getJobGroupId());
        xxlJobInfo.setJobDesc(desc);
        xxlJobInfo.setAuthor("gyhe10");
        xxlJobInfo.setScheduleType("CRON");
        xxlJobInfo.setScheduleConf(cron);
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setExecutorHandler(executorHandler);
        xxlJobInfo.setExecutorParam(param);
        xxlJobInfo.setExecutorRouteStrategy("FIRST");
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        xxlJobInfo.setMisfireStrategy("FIRE_ONCE_NOW");
        xxlJobInfo.setExecutorTimeout(0);
        xxlJobInfo.setExecutorFailRetryCount(0);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        String addAndStartUrl = xxlJobClientProperties.getAddAndStartJobUrl();
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(addAndStartUrl, request, JSONObject.class);
        if (response.getStatusCode().value() == 200 && response.getBody().getInteger("code") == 200) {
            log.info("增加并启动 XXL-JOB 任务成功，返回信息：{}", response.getBody());
            return response.getBody().getLong("content");
        }

        log.error("增加并启动 XXL-JOB 任务失败，返回信息：{}", response.getBody().toJSONString());
        throw new GuiguException(ResultCodeEnum.XXL_JOB_FAIL);
    }
}
